package com.naiterui.ehp.bs.esign.service.impl;

import com.naiterui.common.redis.RedisUtil;
import com.naiterui.ehp.bp.bo.ca.EmrSignBO;
import com.naiterui.ehp.bp.bo.esign.EsignServiceConfigBO;
import com.naiterui.ehp.bp.bo.esign.WillTypeBO;
import com.naiterui.ehp.bp.bo.groupConsult.GroupConsultSignCallbackBO;
import com.naiterui.ehp.bp.bo.groupConsult.GroupConsultSignParamBO;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bs.esign.api.ISignService;
import com.naiterui.ehp.bs.esign.api.bjca.util.SignYwxUtil;
import com.naiterui.ehp.bs.esign.api.bjca.vo.SignFileUploadVO;
import com.naiterui.ehp.bs.esign.api.bjca.vo.YwxUserStatusVO;
import com.naiterui.ehp.bs.esign.api.vo.FaceNoticeVO;
import com.naiterui.ehp.bs.esign.api.vo.SignAccountVO;
import com.naiterui.ehp.bs.esign.api.vo.SignAuthResultVO;
import com.naiterui.ehp.bs.esign.api.vo.SignCallbackVO;
import com.naiterui.ehp.bs.esign.api.vo.SignFileParamVO;
import com.naiterui.ehp.bs.esign.api.vo.SignFileSnVO;
import com.naiterui.ehp.bs.esign.entity.mongo.MedicalRecord;
import com.naiterui.ehp.bs.esign.entity.mysql.EsignDoctor;
import com.naiterui.ehp.bs.esign.entity.mysql.EsignDrMedicationRecom;
import com.naiterui.ehp.bs.esign.entity.mysql.EsignPharmacist;
import com.naiterui.ehp.bs.esign.entity.mysql.EsignPresignFile;
import com.naiterui.ehp.bs.esign.exception.ExceptionCodes;
import com.naiterui.ehp.bs.esign.feign.IDoctorFeignClient;
import com.naiterui.ehp.bs.esign.feign.IEmrFeignClient;
import com.naiterui.ehp.bs.esign.feign.IPharmacistFeignClient;
import com.naiterui.ehp.bs.esign.feign.IRecomFeignClient;
import com.naiterui.ehp.bs.esign.feign.IVideoConsultFeignClient;
import com.naiterui.ehp.bs.esign.repository.mongo.EsignMedicalRecordRepository;
import com.naiterui.ehp.bs.esign.repository.mysql.IEsignDrMedicationRecomRepository;
import com.naiterui.ehp.bs.esign.repository.mysql.IEsignEsignPresignFileRepository;
import com.naiterui.ehp.bs.esign.repository.mysql.IEsignNoSecretRepository;
import com.naiterui.ehp.bs.esign.repository.mysql.IEsignRecomEsignDoctorRepository;
import com.naiterui.ehp.bs.esign.repository.mysql.IEsignRecomEsignPharmacistRepository;
import com.naiterui.ehp.bs.esign.service.IEsignService;
import com.naiterui.ehp.bs.esign.utils.Constants;
import com.naiterui.ehp.bs.esign.utils.SignUtils;
import com.naiterui.ehp.bs.esign.vo.esign.PreSignResultVO;
import com.naiterui.ehp.bs.esign.vo.recom.SignResultVO;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * @author guoyongxiang
 * @date 2019/12/2 11:47
 * @since 1.0.0
 */
@Service
public class EsignServiceImpl implements IEsignService {

    private static final Logger LOGGER = LoggerFactory.getLogger(EsignServiceImpl.class);

    @Value("${file.base.prefix}")
    private String basePath;

    @Autowired
    private IEsignRecomEsignDoctorRepository recomEsignDoctorRepository;
    @Autowired
    private IEsignRecomEsignPharmacistRepository recomEsignPharmacistRepository;
    @Autowired
    private IEsignDrMedicationRecomRepository drMedicationRecomRepository;
    @Autowired
    private IEsignEsignPresignFileRepository esignPresignFileRepository;
    @Autowired
    private EsignMedicalRecordRepository esignMedicalRecordRepository;
    @Autowired
    private IDoctorFeignClient doctorFeignClient;
    @Autowired
    private IPharmacistFeignClient pharmacistFeignClient;
    @Autowired
    private IRecomFeignClient recomFeignClient;

    @Autowired
    private IEmrFeignClient emrFeignClient;
    @Autowired
    private IVideoConsultFeignClient videoConsultFeignClient;

    @Autowired
    private ISignService signService;
    @Autowired
    private IEsignNoSecretRepository esignNoSecretRepository;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String createPersonalSeal(String name, String userType, String typeface) throws BusinessException {
        String sealData = signService.createSeal(null, name, typeface);
        return this.createSealImage(sealData, userType);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public PreSignResultVO preSignPdf(SignFileUploadVO signFileUploadVO, SignAccountVO signAccountVO) throws BusinessException {
        LOGGER.info("同步生成预签名信息：signVO={}", signFileUploadVO.toString());
        //转换成签名vo
        SignFileParamVO paramVO = this.converToSignParam(signFileUploadVO);
        String redisKey = paramVO.getUrId();
        //30秒内禁止重复预签名
        if (RedisUtil.keyOps().existsKey(redisKey)) {
            throw new BusinessException(ExceptionCodes.ESIGN_PRE_SIGN_OFTEN);
        }
        //缓存预签名唯一标识
        RedisUtil.keyOps().expire(redisKey, 30);
        // 查重
        EsignPresignFile esignPresignFile = esignPresignFileRepository.findFirstByFileSnAndType(paramVO.getUrId(),
            this.getFileType(signFileUploadVO.getSignUserType(),  signFileUploadVO.getSignFileType()));
        if (esignPresignFile != null) {
            LOGGER.error("重复请求预签名：uniqueId={}", esignPresignFile.getUniqueId());
            //重新设置同步签名信息的处方唯一标识
            paramVO.setUrId(paramVO.getUrId() + "_" + RandomUtils.nextLong());
        }
        //此处为了做兼容，后期可去掉
        signAccountVO.setOpenId(signAccountVO.getOpenId());
        paramVO.setSignFileType(signFileUploadVO.getSignFileType());
        // CA 电子签名预签署
        PreSignResultVO resultVO = signService.preSign(paramVO, signAccountVO);
        String uniqueId = resultVO.getUniqueId();

        if (esignPresignFile == null) {
            // 保存预签文件表
            String relativePath = signFileUploadVO.getPdfPath().replaceAll(basePath, "");
            esignPresignFile =
                EsignPresignFile.builder()
                    .uniqueId(uniqueId)
                    .fileSn(paramVO.getUrId())
                    .type(this.getFileType(signFileUploadVO.getSignUserType(),
                        signFileUploadVO.getSignFileType()))
                    .path(relativePath)
                    .createdAt(new Date())
                    .changedAt(new Date())
                    .build();
            esignPresignFileRepository.save(esignPresignFile);
        } else {
            esignPresignFile.setUniqueId(uniqueId);
            esignPresignFile.setChangedAt(new Date());
            esignPresignFileRepository.update(esignPresignFile);
        }

        return resultVO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void userAuth(String openId, String phone, String status, String reason) throws BusinessException {
        this.userAuth(SignAuthResultVO.builder()
            .openId(openId)
            .phone(phone)
            .status(status)
            .reason(reason)
            .build());
    }

    @Override
    public void userAuth(SignAuthResultVO resultVO) throws BusinessException {
        String openId = resultVO.getOpenId();
        String phone = resultVO.getPhone();
        String status = resultVO.getStatus();
        String reason = resultVO.getReason();
        Integer authStatus = null;

        //设置签名图片转换
        String imagePath = "";
        if (StringUtils.isNotBlank(resultVO.getSealData())) {
            if (Constants.USER_TITLE_DR.equals(resultVO.getTitle())) {
                imagePath = Constants.SEAL_PATH_PRE_DR + resultVO.getOpenId() + "_" + System.currentTimeMillis() + ".png";
            } else {
                imagePath = Constants.SEAL_PATH_PRE_PH + resultVO.getOpenId() + "_" + System.currentTimeMillis() + ".png";
            }

            SignUtils.decoderBase64File(resultVO.getSealData(), imagePath);
        } else {
            //未通过签名服务生成的，取用户自定义签名
            imagePath = resultVO.getSealImagePath();
        }

        EsignDoctor doctor = recomEsignDoctorRepository.findFirstByOpenId(openId);
        EsignPharmacist pharmacist = recomEsignPharmacistRepository.findFirstByOpenId(openId);
        boolean isEsignDoctor = null != doctor ? true : false;
        boolean isEsignPharmacist = null != pharmacist ? true : false;

        if (status != null) {
            switch (resultVO.getStatus()) {
                case SignAuthResultVO.PROCESS_AUDIT_PASS:
                    LOGGER.info("医网信更新用户状态-审核通过 openId:{}, phone:{}, status:{}, reason:{}", openId, phone, status, reason);
                    // 审核通过
                    authStatus = EsignDoctor.AUTH_STATUS_PASS;
                    break;

                case SignAuthResultVO.PROCESS_APPLY_REJECT:
                    LOGGER.info("医网信更新用户状态-审核不通过 openId:{}, phone:{}, status:{}, reason:{}", openId, phone, status, reason);
                    // 审核不通过
                    authStatus = EsignDoctor.AUTH_STATUS_NOT_PASS;
                    break;

                case SignAuthResultVO.PROCESS_CA_ISSUE:
                    LOGGER.info("医网信更新用户状态(未处理)-证书签发 openId:{}, phone:{}, status:{}", openId, phone, status);
                    if (isEsignDoctor && StringUtils.isEmpty(doctor.getSealImage()) && StringUtils.isEmpty(imagePath)) {
                        imagePath = this.getImagePath(openId, SignFileSnVO.USER_TYPE_DR);
                        doctor.setSealImage(imagePath);
                        doctorFeignClient.perfectSealImage(imagePath, doctor.getDoctorId());
                    } else if (isEsignPharmacist && StringUtils.isEmpty(pharmacist.getSealImage()) && StringUtils.isEmpty(imagePath)) {
                        imagePath = this.getImagePath(openId, SignFileSnVO.USER_TYPE_PH);
                        pharmacist.setSealImage(imagePath);
                        pharmacistFeignClient.perfectSealImage(imagePath, pharmacist.getPharmacistId());
                    }
                    return;

                case SignAuthResultVO.PROCESS_SET_STAMP:
                    LOGGER.info("医网信更新用户状态(未处理)-设置签章 openId:{}, phone:{}, status:{}", openId, phone, status);
                    return;

                case SignAuthResultVO.PROCESS_USER_LOGOFF:
                    LOGGER.info("医网信更新用户状态(未处理)-用户注销 openId:{}, phone:{}, status:{}", openId, phone, status);
                    return;

                case SignAuthResultVO.PROCESS_UPDATE_PHONE:
                    LOGGER.info("医网信更新用户状态(未处理)-修改手机号 openId:{}, phone:{}, status:{}", openId, phone, status);
                    if (isEsignDoctor) {
                        doctor.setPhone(phone);
                        recomEsignDoctorRepository.update(doctor);
                    } else if (isEsignPharmacist) {
                        pharmacist.setPhone(phone);
                        recomEsignPharmacistRepository.update(pharmacist);
                    }
                    return;

                default:
                    LOGGER.info("医网信更新用户状态(未定义) openId:{}, phone:{}, status:{}, reason:{}", openId, phone, status, reason);
                    authStatus = EsignDoctor.AUTH_STATUS_DEF;
                    break;
            }
        }

        if (isEsignDoctor) {
            if (authStatus != null) {
                doctor.setAuthStatus(authStatus);
            }
            doctor.setPhone(phone);
            doctor.setReason(reason);
            doctor.setChangedAt(new Date());
            doctor.setSealImage(imagePath);

            recomEsignDoctorRepository.update(doctor);

            // 医生签名回调(userId, status, reason)
            doctorFeignClient.esignAuth(doctor.getDoctorId(), authStatus, reason);
        } else {

            if (pharmacist != null) {
                if (authStatus != null) {
                    pharmacist.setAuthStatus(authStatus);
                }
                pharmacist.setPhone(phone);
                pharmacist.setReason(reason);
                pharmacist.setChangedAt(new Date());
                pharmacist.setSealImage(imagePath);

                recomEsignPharmacistRepository.update(pharmacist);

                // 药师签名回调(userId, status, reason)
                pharmacistFeignClient.esignAuth(pharmacist.getPharmacistId(), authStatus, reason);
            } else {
                LOGGER.warn("医网信更新用户状态, openId不存在:{}, phone:{}, status:{}, reason:{}", openId, phone, status, reason);
            }
        }
    }

    public String getImagePath(String openId, String userType) throws BusinessException {
        // 三方机构为CA情况下，CA负责生成签章图片，回写医生、电子签名医师、电子签名药师用户医网信生成的签章图片地址
        String imagePath = "";
        YwxUserStatusVO result = SignYwxUtil.getUserStatusDetail(openId);
        LOGGER.info("调用医网信查询接口获取医网信生成签名图片结果为：{}", result.toString());
        if (userType.equals(SignFileSnVO.USER_TYPE_DR)) {
            imagePath = Constants.SEAL_PATH_PRE_DR + openId + "_" + System.currentTimeMillis() + ".png";
        } else if (userType.equals(SignFileSnVO.USER_TYPE_PH)) {
            imagePath = Constants.SEAL_PATH_PRE_PH + openId + "_" + System.currentTimeMillis() + ".png";
        }
        SignUtils.decoderBase64File(result.getStamp(), imagePath);
        imagePath = imagePath.replace(basePath, "");
        return imagePath;
    }

    @Override
    public void sign(SignFileUploadVO signFileUploadVO, SignAccountVO signAccountVO) throws BusinessException {
        //转换成签名vo
        SignFileParamVO paramVO = this.converToSignParam(signFileUploadVO);
        signAccountVO.setXingkaiSealImage(this.createPersonalSeal(signAccountVO.getName(), signAccountVO.getUserType(),Constants.TYPEFACE_ZHENGKAI));
        signService.sign(paramVO, signAccountVO, this);
    }

    /**
     * 签名结果异步处理
     *
     * @param signCallbackVO
     *
     * @throws BusinessException
     */
    @Async
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void signResult(SignCallbackVO signCallbackVO) throws BusinessException {
        SignFileSnVO signFileSnVO = SignFileSnVO.init(signCallbackVO.getUrId());
        String urId = SignFileSnVO.getFileSn(Constants.SIGN_FILENAME_PRE, signFileSnVO.getFileType(), signFileSnVO.getUserType(),
            signFileSnVO.getUserId(), signFileSnVO.getBizSn());
        Integer fileType = this.getFileType(signFileSnVO.getUserType(), signFileSnVO.getFileType());
        EsignPresignFile presignFile = esignPresignFileRepository.findFirstByFileSnAndType(urId, fileType);
        String signPath = "";

        if (presignFile == null) {
            LOGGER.warn("未记录电子签名回调");
            throw new BusinessException(ExceptionCodes.ILLEGAL_REQUEST, "当前处方尚未进行签署意愿认证，请先进行意愿认证");
        }

        switch (signFileSnVO.getFileType()) {
            case SignFileSnVO.FILE_TYPE_RP:
                signPath = this.signedHandleRecipel(signCallbackVO, signFileSnVO);
                break;
            case SignFileSnVO.FILE_TYPE_EMR:
                signPath = this.signedHandleEmr(signCallbackVO, signFileSnVO);
                break;
            case SignFileSnVO.FILE_TYPE_NS:
                signPath = this.signedHandleNs(signCallbackVO, signFileSnVO);
                break;
            case SignFileSnVO.FILE_TYPE_GROUPCONSULT:
                signPath = this.signedHandleGC(signCallbackVO, signFileSnVO);
                break;
            default:
                LOGGER.warn("签名结果回调，未知的签名文件类型 uniqueId:{}, status:{}, reason:{}, urId:{}", signCallbackVO.getUniqueId(), signCallbackVO.getStatus(),
                        signCallbackVO.getReason(),
                        signCallbackVO.getUrId());
        }

        presignFile.setSignPath(signPath);
        presignFile.setChangedAt(new Date());
        esignPresignFileRepository.update(presignFile);
    }

    @Override
    public void faceNotice(FaceNoticeVO faceNoticeVO) {
        //todo: 保存认证结果
    }


    @Override
    public Integer getUserAuthStatus(Long userId, String userType) throws BusinessException {
        Integer authStatus = 0;
        if (Constants.USER_TITLE_DR.equals(userType)) {
            EsignDoctor doctor = recomEsignDoctorRepository.findFirstByDoctorId(userId);
            if (doctor != null) {
                authStatus = doctor.getAuthStatus();
            }

        } else {
            EsignPharmacist pharmacist = recomEsignPharmacistRepository.findFirstByPharmacistId(userId);
            if (pharmacist != null) {
                authStatus = pharmacist.getAuthStatus();
            }
        }
        return authStatus;
    }

    @Override
    public Map<String, String> getYwxSignConfig() throws BusinessException {
        Map<String, String> map = new HashMap<>();
        map.put("clientId", SignYwxUtil.CLIENT_ID);
        map.put("secret", SignYwxUtil.APP_SECRET);
        return map;
    }

    @Override
    public List<WillTypeBO> getWillTypes(String willType) throws BusinessException {
        EsignServiceConfigBO serviceConfigBO = signService.getServiceConfig();

        if (serviceConfigBO.getWillTypes().size() < 1) {
            LOGGER.warn("签名厂商签署列表未配置，请完善【EsignWillTypeEnum】对应厂商配置配置, 厂商:{}", signService.getCurrentServiceProvider().getProviderName());
            throw new BusinessException(ExceptionCodes.PARAM_ERROR, "签名厂商签署列表未配置");
        }
        
        // 未指定意愿签署方式则指定第一个为默认
        if (StringUtils.isBlank(willType)) {
            serviceConfigBO.getWillTypes().get(0).setChecked(true);
        } else {
            String wt = willType;
            serviceConfigBO.getWillTypes().forEach(w -> {
                if (w.getValue().equals(wt)) {
                    w.setChecked(true);
                }
            });
        }
        return serviceConfigBO.getWillTypes();
    }

    /**
     * 统一转换成签名vo
     *
     * @param signFileUploadVO
     *
     * @return
     *
     * @throws BusinessException
     */
    private SignFileParamVO converToSignParam(SignFileUploadVO signFileUploadVO) throws BusinessException {
        File file = new File(signFileUploadVO.getPdfPath());
        if (!file.exists()) {
            throw new BusinessException(ExceptionCodes.FILE_NOT_EXIST);
        }
        String base64Str = SignUtils.encodeBase64File(signFileUploadVO.getPdfPath());

        String urId = SignFileSnVO.getFileSn(Constants.SIGN_FILENAME_PRE, signFileUploadVO.getSignFileType(), signFileUploadVO.getSignUserType(),
                                             signFileUploadVO.getSignUserId(), signFileUploadVO.getBizSn());

        SignFileParamVO paramVO = new SignFileParamVO();
        paramVO.setUrId(urId);
        paramVO.setUnionId(signFileUploadVO.getUnionId());
        paramVO.setPatientAge(signFileUploadVO.getPatientAge());
        paramVO.setPatientCard("");
        paramVO.setPatientCardType("QT");
        paramVO.setPatientName(signFileUploadVO.getPatientName());
        String sex = signFileUploadVO.getPatientGender().equals(0) ? "女" : "男";
        paramVO.setPatientSex(sex);
        paramVO.setRecipeTime(signFileUploadVO.getCreatedAt());
        paramVO.setLocationPage(1);
        paramVO.setPdfBase64(base64Str);
        paramVO.setPdfPath(signFileUploadVO.getPdfPath());
        paramVO.setOutputPath(signFileUploadVO.getOutputPath());
        paramVO.setKeyword(signFileUploadVO.getKeyword());
        paramVO.setX(signFileUploadVO.getStampX());
        paramVO.setY(signFileUploadVO.getStampY());
        paramVO.setAddSignTime(signFileUploadVO.getAddSignTime());

        return paramVO;

    }


    /**
     * 获取医生已签名文件路径
     * /{basePath}/dr/{drId}/{ptId}_{recomSn}/{drId}_{ptId}_{recomSn}.pdf
     *
     * @param doctorId
     * @param patientId
     * @param recomSn
     *
     * @return
     */
    public String getRecomDrSignPath(Long doctorId, Long patientId, String recomSn) {
        String path = Constants.PREC_BASE_PATH_PREFIX + "/dr/%d/%d_%s/%d_%d_%s.pdf";
        return String.format(path, doctorId, patientId, recomSn, doctorId, patientId, recomSn);
    }

    /**
     * 获取药师已签名文件路径
     * /{basePath}/ph/{drId}/{ptId}_{recomSn}/{drId}_{ptId}_{recomSn}.pdf
     *
     * @param doctorId
     * @param patientId
     * @param recomSn
     *
     * @return
     */
    public String getRecomPhSignPath(Long doctorId, Long patientId, String recomSn) {
        String path = Constants.PREC_BASE_PATH_PREFIX + "/ph/%d/%d_%s/%d_%d_%s.pdf";
        return String.format(path, doctorId, patientId, recomSn, doctorId, patientId, recomSn);
    }

    /**
     * 获取调配药师已签名文件路径
     * /{basePath}/al/ph/{drId}/{ptId}_{recomSn}/{drId}_{ptId}_{recomSn}.pdf
     *
     * @param doctorId
     * @param patientId
     * @param recomSn
     *
     * @return
     */
    public String getRecomAlPhSignPath(Long doctorId, Long patientId, String recomSn) {
        String path = Constants.PREC_BASE_PATH_PREFIX + "/al/ph/%d/%d_%s/%d_%d_%s.pdf";
        return String.format(path, doctorId, patientId, recomSn, doctorId, patientId, recomSn);
    }
    public Integer getFileType(String signUserType, String signFileType) {
        Integer type = 0;
        if (SignFileSnVO.FILE_TYPE_RP.equals(signFileType)) {
            if (SignFileSnVO.USER_TYPE_DR.equals(signUserType)) {
                // 处方医师
                type = EsignPresignFile.TYPE_RECIPEL_DR;
            } else if (SignFileSnVO.USER_TYPE_PH.equals(signUserType)) {
                type = EsignPresignFile.TYPE_RECIPEL_PH;
            } else {
                type = EsignPresignFile.TYPE_RECIPEL_AL_PH;
            }
        } else if (SignFileSnVO.FILE_TYPE_EMR.equals(signFileType)) {
            type = EsignPresignFile.TYPE_EMR_DR;
        } else if (SignFileSnVO.FILE_TYPE_NS.equals(signFileType)) {
            if (SignFileSnVO.USER_TYPE_DR.equals(signUserType)) {
                // 免签医生
                type = EsignPresignFile.TYPE_NO_SECRET_DR;
            } else {
                type = EsignPresignFile.TYPE_NO_SECRET_PH;
            }
        } else if (SignFileSnVO.FILE_TYPE_GROUPCONSULT.equals(signFileType)) {
            if (SignFileSnVO.USER_TYPE_DR.equals(signUserType)) {
                // 发起医师
                type = EsignPresignFile.TYPE_GROUPCONSULT_SOURCE;
            } else {
                // 受邀专家
                type = EsignPresignFile.TYPE_GROUPCONSULT_TARGET;
            }
        }
        return type;
    }

    /**
     * 处理处方签名结果
     *
     * @param signCallbackVO
     * @param signFileSnVO
     *
     * @return
     *
     * @throws Exception
     */
    private String signedHandleRecipel(SignCallbackVO signCallbackVO, SignFileSnVO signFileSnVO) throws BusinessException {
        String signPath = "";
        EsignDrMedicationRecom recom = drMedicationRecomRepository.findBySerialNumber(signFileSnVO.getBizSn());
        // 处方签名结果回调
        if (SignFileSnVO.USER_TYPE_DR.equals(signFileSnVO.getUserType())) {
            signPath = this.getRecomDrSignPath(recom.getDoctorId(), recom.getPatientId(), recom.getSerialNumber());
        } else if (SignFileSnVO.USER_TYPE_PH.equals(signFileSnVO.getUserType())){
            signPath = this.getRecomPhSignPath(recom.getDoctorId(), recom.getPatientId(), recom.getSerialNumber());
        } else {
            signPath = this.getRecomAlPhSignPath(recom.getDoctorId(), recom.getPatientId(), recom.getSerialNumber());
        }
        Integer signStatus = SignResultVO.SIGN_STATUS_FAIL;
        // 校验签名状态
        if (SignCallbackVO.STATUS_SIGNED.equals(signCallbackVO.getStatus())) {
            LOGGER.info("电子签名回调——处方，回调成功，准备写签名文件：recomId:{}, recomSn:{}, signUserType:{}, urId:{}, uniqueId:{}", recom.getId(),
                    recom.getSerialNumber(), signFileSnVO.getUserType(), signCallbackVO.getUrId(), signCallbackVO.getUniqueId());
            SignUtils.decoderBase64File(signCallbackVO.getSignedPdfBase64(), basePath + signPath);
            LOGGER.info("电子签名回调-处方, 处理成功 recomId:{}, recomSn:{}, signUserType:{}, urId:{}, uniqueId:{}", recom.getId(),
                    recom.getSerialNumber(),
                    signFileSnVO.getUserType(), signCallbackVO.getUrId(), signCallbackVO.getUniqueId());
            signStatus = SignResultVO.SIGN_STATUS_SUCCESS;
        } else {
            signPath = "";
            LOGGER.warn("电子签名回调-处方，签名状态异常 uniqueId:{}, status:{}, reason:{}, urId:{}", signCallbackVO.getUniqueId(),
                        signCallbackVO.getStatus(),
                        signCallbackVO.getReason(),
                        signCallbackVO.getUrId());
        }

        // 回调签名结果(fileSn, status, time, path)
        SignResultVO signResultVO = SignResultVO.builder()
                                                .userType(Integer.valueOf(signFileSnVO.getUserType()))
                                                .fileSn(signCallbackVO.getUrId())
                                                .bizSn(signFileSnVO.getBizSn())
                                                .status(signStatus)
                                                .signTime(signCallbackVO.getSignTime() == null ? new Date() : signCallbackVO.getSignTime())
                                                .path(signPath).build();
        recomFeignClient.signResult(signResultVO);
        LOGGER.info("回调签名结果保存成功: signResultVO={}", signResultVO);
        return signPath;
    }

    private String signedHandleEmr(SignCallbackVO signCallbackVO, SignFileSnVO signFileSnVO) throws BusinessException {

        MedicalRecord record = esignMedicalRecordRepository.get(signFileSnVO.getBizSn());
        String signPath = Constants.EMR_PDF_FILE_BASE_PATH + record.getPatientId() + "/esign/" + record.getId() + ".pdf";

        Integer signStatus = SignResultVO.SIGN_STATUS_FAIL;
        // 校验签名状态
        if (SignCallbackVO.STATUS_SIGNED.equals(signCallbackVO.getStatus())) {
            SignUtils.decoderBase64File(signCallbackVO.getSignedPdfBase64(), basePath + signPath);
            LOGGER.info("电子签名回调-病例, 处理成功 emrId:{}, signUserType:{}, urId:{}, uniqueId:{}", record.getId(),
                    signFileSnVO.getUserType(), signCallbackVO.getUrId(), signCallbackVO.getUniqueId());
            signStatus = SignResultVO.SIGN_STATUS_SUCCESS;
        } else {
            signPath = "";
            LOGGER.warn("电子签名回调-病例，签名状态异常 uniqueId:{}, status:{}, reason:{}, urId:{}", signCallbackVO.getUniqueId(),
                    signCallbackVO.getStatus(),
                    signCallbackVO.getReason(),
                    signCallbackVO.getUrId());
        }

        // 回调签名结果
        EmrSignBO signResultVO = EmrSignBO.builder()
                                          .id(record.getId())
                                          .filePath(signPath)
                                          .uniqueId(signCallbackVO.getUniqueId())
                                          .status(signStatus)
                                          .sealImage(signCallbackVO.getSealImage())
                                          .signTime(signCallbackVO.getSignTime())
                                          .createdAt(new Date())
                                          .build();
        emrFeignClient.signResult(signResultVO);

        return signPath;
    }

    /**
     * 处理免密签名结果
     * @param signCallbackVO
     * @param signFileSnVO
     * @return
     * @throws BusinessException
     */
    private String signedHandleNs(SignCallbackVO signCallbackVO, SignFileSnVO signFileSnVO) throws BusinessException {
        String signPath;
        if (SignFileSnVO.USER_TYPE_DR.equals(signFileSnVO.getUserType())){
            signPath =
                Constants.ESIGN_INFORM_PATH_DR + signFileSnVO.getUserId() + "/" + signFileSnVO.getBizSn() + ".pdf";
        } else {
            signPath =
                Constants.ESIGN_INFORM_PATH_PH + signFileSnVO.getUserId() + "/" + signFileSnVO.getBizSn() + ".pdf";
        }

        Integer signStatus = SignResultVO.SIGN_STATUS_FAIL;
        // 校验签名状态
        if (SignCallbackVO.STATUS_SIGNED.equals(signCallbackVO.getStatus())) {
            SignUtils.decoderBase64File(signCallbackVO.getSignedPdfBase64(), basePath + signPath);
            LOGGER.info("电子签名回调-免密, 处理成功 noSecretId:{}, signUserType:{}, urId:{}, uniqueId:{}", signFileSnVO.getBizSn(),
                    signFileSnVO.getUserType(), signCallbackVO.getUrId(), signCallbackVO.getUniqueId());
            signStatus = SignResultVO.SIGN_STATUS_SUCCESS;
        } else {
            signPath = "";
            LOGGER.warn("电子签名回调-免密，签名状态异常 uniqueId:{}, status:{}, reason:{}, urId:{}", signCallbackVO.getUniqueId(),
                    signCallbackVO.getStatus(),
                    signCallbackVO.getReason(),
                    signCallbackVO.getUrId());
        }
        esignNoSecretRepository.updateSignUrlStatusSignTime(signPath, signStatus, signCallbackVO.getSignTime(),
                Long.valueOf(signFileSnVO.getBizSn()));
        return signPath;
    }

    /**
     * 处理会诊签名
     */
    private String signedHandleGC(SignCallbackVO signCallbackVO, SignFileSnVO signFileSnVO) throws BusinessException {
        String signPath;
        int optionType;
        if (SignFileSnVO.USER_TYPE_DR.equals(signFileSnVO.getUserType())) {
            signPath = Constants.ESIGN_SOURCE_DR_PATH + signFileSnVO.getUserId() + "/" + signFileSnVO.getBizSn() + ".pdf";
            optionType = GroupConsultSignParamBO.OPTION_TYPE_SOURCE;
        } else {
            signPath = Constants.ESIGN_TARGET_DR_PATH + signFileSnVO.getUserId() + "/" + signFileSnVO.getBizSn() + ".pdf";
            optionType = GroupConsultSignParamBO.OPTION_TYPE_TARGET;
        }

        Integer signStatus = SignResultVO.SIGN_STATUS_FAIL;
        // 校验签名状态
        if (SignCallbackVO.STATUS_SIGNED.equals(signCallbackVO.getStatus())) {
            SignUtils.decoderBase64File(signCallbackVO.getSignedPdfBase64(), basePath + signPath);
            LOGGER.info("会诊单电子签名回调, 处理成功 groupConsultId:{}, signUserType:{}, urId:{}, uniqueId:{}",
                    signFileSnVO.getBizSn(),
                    signFileSnVO.getUserType(),
                    signCallbackVO.getUrId(),
                    signCallbackVO.getUniqueId());
            signStatus = SignResultVO.SIGN_STATUS_SUCCESS;
        } else {
            signPath = "";
            LOGGER.warn("会诊单电子签名回调，签名状态异常 uniqueId:{}, status:{}, reason:{}, urId:{}", signCallbackVO.getUniqueId(),
                    signCallbackVO.getStatus(),
                    signCallbackVO.getReason(),
                    signCallbackVO.getUrId());
        }

        // 回调签名结果
        GroupConsultSignCallbackBO signResultVO = GroupConsultSignCallbackBO.builder()
                .opinionType(optionType)
                .groupConsultId(Long.valueOf(signFileSnVO.getBizSn()))
                .filePath(signPath)
                .uniqueId(signCallbackVO.getUniqueId())
                .status(signStatus)
                .sealImage(signCallbackVO.getSealImage())
                .signTime(signCallbackVO.getSignTime())
                .createdAt(new Date())
                .build();
        videoConsultFeignClient.signResult(signResultVO);
        return signPath;
    }

    /**
     * 签名服务生成签名字符串生成签名图片文件
     *
     * @param sealData
     * @param userType
     *
     * @return
     *
     * @throws BusinessException
     */
    public String createSealImage(String sealData, String userType) throws BusinessException {
        String imagePath;
        if(Constants.USER_TITLE_AL_PH.equals(userType)){
            imagePath = Constants.SEAL_PATH_PRE_AL_PH + UUID.randomUUID().toString() + "_" + System.currentTimeMillis() + ".png";
        } else {
            imagePath = Constants.SEAL_PATH_PRE_PH + UUID.randomUUID().toString() + "_" + System.currentTimeMillis() + ".png";
        }
        SignUtils.decoderBase64File(sealData, imagePath);
        imagePath = imagePath.replace(Constants.BASE_PATH, "");
        return imagePath;
    }

}
